package com.mashibing.mall.product.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mashibing.common.dto.SkuReductionDTO;
import com.mashibing.common.dto.SpuBoundsDTO;
import com.mashibing.common.exception.BusinessException;
import com.mashibing.common.utils.R;
import com.mashibing.mall.product.entity.*;
import com.mashibing.mall.product.feign.CouponFeignService;
import com.mashibing.mall.product.service.*;
import com.mashibing.mall.product.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mashibing.common.utils.PageUtils;
import com.mashibing.common.utils.Query;

import com.mashibing.mall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

/**
 * spu信息 Service 实现类
 */
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Resource
    private CategoryService categoryService;

    @Resource
    private BrandService brandService;

    @Resource
    private SpuInfoDescService spuInfoDescService;

    @Resource
    private SpuImagesService spuImagesService;

    @Resource
    private AttrService attrService;

    @Resource
    private ProductAttrValueServiceImpl productAttrValueService;

    @Resource
    private SkuInfoService skuInfoService;

    @Resource
    private SkuImagesService skuImagesService;

    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Resource
    private CouponFeignService couponFeignService;

    /**
     * spu信息 - 分页
     */
    @Override
    public PageUtils queryPageSPU(Map<String, Object> params) {

        QueryWrapper<SpuInfoEntity> queryWrapper = this.buildQueryWrapper(params);
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                queryWrapper
        );

        // 根据查询到的分页信息，再查询出对应的类别名称和品牌名称
        List<SpuInfoVO> spuInfoVOList = page.getRecords().stream().map(spu -> {

            // 分类 id
            Long catalogId = spu.getCatalogId();

            // 根据分类 id 查找分类名称
            CategoryEntity category = categoryService.getById(catalogId);

            // 品牌 id
            Long brandId = spu.getBrandId();

            // 根据品牌 id 查找品牌名称
            BrandEntity brand = brandService.getById(brandId);

            // 构建 spu 信息对象
            SpuInfoVO spuInfoVO = new SpuInfoVO();

            BeanUtils.copyProperties(spu, spuInfoVO);
            spuInfoVO.setCatalogName(category.getName());
            spuInfoVO.setBrandName(category.getName());

            return spuInfoVO;
        }).collect(Collectors.toList());

        // 设置分页信息
        IPage<SpuInfoVO> iPage = new Page<SpuInfoVO>();
        iPage.setRecords(spuInfoVOList);
        iPage.setPages(page.getPages());
        iPage.setCurrent(page.getCurrent());

        return new PageUtils(iPage);
    }


    /**
     * spu信息 - 保存
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuInfoVO spuInfoVo) {

        // 如果 spu 信息为空，则抛出异常
        if (ObjectUtil.isEmpty(spuInfoVo)) {
            throw new BusinessException("spu 信息不能为空！");
        }

        /* 1.保存spu的基本信息 pms_spu_info */
        // 根据商品名称查找 spu 信息
        LambdaQueryWrapper<SpuInfoEntity> spuInfoEntityQw = new LambdaQueryWrapper<>();
        spuInfoEntityQw.eq(SpuInfoEntity::getSpuName, spuInfoVo.getSpuName());
        List<SpuInfoEntity> spuInfoEntityList = this.list(spuInfoEntityQw);

        // 如果 spu 信息列表不为空，则抛出异常
        if (CollectionUtil.isNotEmpty(spuInfoEntityList))
            throw new BusinessException("spu 商品名称不能重复！");

        // 根据分类 id 查找分类
        CategoryEntity category = categoryService.getById(spuInfoVo.getCatalogId());

        // 如果分类为空，则抛出异常
        if (ObjectUtil.isEmpty(category))
            throw new BusinessException("分类信息不存在！");

        // 如果当前分类不是三级分类，则抛出异常
        if (ObjectUtil.isEmpty(category.getCatLevel()) || category.getCatLevel() != 3)
            throw new BusinessException("三级分类才能创建商品！");

        // 根据品牌 id 查找品牌
        LambdaQueryWrapper<BrandEntity> brandServiceQw = new LambdaQueryWrapper<>();
        brandServiceQw.eq(BrandEntity::getBrandId, spuInfoVo.getBrandId());
        BrandEntity brand = brandService.getOne(brandServiceQw);

        // 如果品牌不存在，则抛出异常
        if (ObjectUtil.isEmpty(brand))
            throw new BusinessException("品牌信息不存在！");

        // 保存 spu 信息
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        spuInfoEntity.setSpuName(spuInfoVo.getSpuName());
        spuInfoEntity.setSpuDescription(spuInfoVo.getSpuDescription());
        spuInfoEntity.setCatalogId(spuInfoVo.getCatalogId());
        spuInfoEntity.setBrandId(spuInfoVo.getBrandId());
        spuInfoEntity.setWeight(spuInfoVo.getWeight());
        spuInfoEntity.setPublishStatus(0); // 设置状态为新建状态
        // todo 以后使用 mybatis plus sql 拦截器自动填充时间
        spuInfoEntity.setCreateTime(new java.util.Date());
        spuInfoEntity.setUpdateTime(new java.util.Date());
        this.save(spuInfoEntity);

        // 2.保存spu的详情信息 pms_spu_info_desc */
        // 根据 spu id 查找 spu 详情信息
        SpuInfoDescEntity spuInfoDesc = spuInfoDescService.getById(spuInfoEntity.getId());

        // 如果 spu 详情信息不为空，则抛出异常
        if (ObjectUtil.isNotEmpty(spuInfoDesc))
            throw new BusinessException("spu 详情信息已存在！");

        // 保存 spu 详情信息
        List<String> decripts = spuInfoVo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        spuInfoDescEntity.setDecript(String.join(",", decripts));
        spuInfoDescService.save(spuInfoDescEntity);

        // 3.保存图片信息 pms_spu_images */
        // 获取 spu 图片列表
        List<String> images = spuInfoVo.getImages();

        // 将图片封装为一个 SpuImagesEntity 对象，并保存到数据库中
        List<SpuImagesEntity> spuImagesEntityList = images.stream().map(image -> {
            SpuImagesEntity imagesEntity = new SpuImagesEntity();
            imagesEntity.setSpuId(spuInfoEntity.getId());
            imagesEntity.setImgUrl(image);
            return imagesEntity;
        }).collect(Collectors.toList());

        // 批量保存图片信息
        spuImagesService.saveBatch(spuImagesEntityList);

        // 4.保存规格参数 pms_product_attr_value */
        // 获取规格参数列表
        List<BaseAttrs> baseAttrsList = spuInfoVo.getBaseAttrs();

        // 获取规格参数的属性 id 集合
        Set<Long> attrIdSet = baseAttrsList.stream().map(BaseAttrs::getAttrId).collect(Collectors.toSet());

        // 根据属性 id 集合查找商品属性列表
        List<AttrEntity> attrEntities = attrService.listByIds(attrIdSet);

        // 如果商品属性列表和属性 id 集合长度不一致，则抛出异常
        if (attrEntities.size() != attrIdSet.size())
            throw new BusinessException("商品属性信息不存在！");

        // 转换为属性 id 和商品属性的映射
        Map<Long, AttrEntity> attrEntityMap = attrEntities.stream().collect(Collectors.toMap(AttrEntity::getAttrId, attr -> attr));

        // 封装待添加的规格参数列表
        List<ProductAttrValueEntity> productAttrValueEntityList = baseAttrsList.stream().map(baseAttrs -> {

            // 构建待添加的 spu 属性
            ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();

            // 设置 spu id
            productAttrValueEntity.setSpuId(spuInfoEntity.getId());

            // 设置属性 id
            productAttrValueEntity.setAttrId(baseAttrs.getAttrId());

            // 根据属性 id 查找属性
            AttrEntity attrEntity = attrEntityMap.get(baseAttrs.getAttrId());

            // 设置属性名
            productAttrValueEntity.setAttrName(attrEntity.getAttrName());

            // 设置是否可以快速展示
            productAttrValueEntity.setQuickShow(baseAttrs.getShowDesc());

            // 返回待添加的 spu 属性
            return productAttrValueEntity;

        }).collect(Collectors.toList());

        // 保存规格参数列表
        productAttrValueService.saveBatch(productAttrValueEntityList);

        // 5.保存当前 spu 对应的所有 sku 信息 */
        // 获取 sku 信息参数列表
        List<Skus> skusParamList = spuInfoVo.getSkus();

        // 如果 sku 信息列表为空，则抛出异常
        if (CollectionUtil.isEmpty(skusParamList))
            throw new BusinessException("sku 信息不能为空！");

        // 获取 sku 名称集合
        Set<String> skuNameSet = skusParamList.stream().map(Skus::getSkuName).collect(Collectors.toSet());

        // 根据 sku 名称集合查找 sku 信息列表
        LambdaQueryWrapper<SkuInfoEntity> skuInfoEntityQw = new LambdaQueryWrapper<>();
        skuInfoEntityQw.in(SkuInfoEntity::getSkuName, skuNameSet);
        List<SkuInfoEntity> skuInfoEntityList = skuInfoService.list(skuInfoEntityQw);

        // 如果 sku 信息列表不为空，则抛出异常
        if (CollectionUtil.isNotEmpty(skuInfoEntityList))
            throw new BusinessException("sku 名称不能重复！");

        // 5.1 保存 sku 的基本信息 pms_sku_info */
        // 遍历 sku 信息参数列表
        for (Skus sku : skusParamList) {

            // 构建待添加的 sku 信息
            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();

            // 设置 sku 名称、标题、副标题、价格
            skuInfoEntity.setSkuName(sku.getSkuName());
            skuInfoEntity.setSkuTitle(sku.getSkuTitle());
            skuInfoEntity.setSkuSubtitle(sku.getSkuSubtitle());
            skuInfoEntity.setPrice(sku.getPrice());

            // 设置品牌 id、分类 id、 spu id、销量
            skuInfoEntity.setBrandId(spuInfoVo.getBrandId());
            skuInfoEntity.setCatalogId(spuInfoVo.getCatalogId());
            skuInfoEntity.setSpuId(spuInfoEntity.getId());
            skuInfoEntity.setSaleCount(0L);

            // 获取 sku 图片列表
            List<Images> skuImages = sku.getImages();

            // 默认图片
            String defaultImage = "";

            // 遍历 sku 图片列表
            for (Images image : skuImages) {

                // 如果当前图片为默认图片，则设置默认图片
                if (image.getDefaultImg() == 1) {
                    defaultImage = image.getImgUrl();
                    break;
                }
            }

            // 设置默认图片
            skuInfoEntity.setSkuDefaultImg(defaultImage);

            // 保存 sku 信息
            skuInfoService.save(skuInfoEntity);

            // 5.2 保存 sku 的图片信息 pms_sku_images */
            List<SkuImagesEntity> skuImagesEntityList = skuImages.stream().map(img -> {

                // 构建待添加的 sku 图片信息
                SkuImagesEntity skuImagesEntity = new SkuImagesEntity();

                // 设置 sku id、sku id、默认图片
                skuImagesEntity.setSkuId(spuInfoEntity.getId());
                skuImagesEntity.setImgUrl(img.getImgUrl());
                skuImagesEntity.setDefaultImg(img.getDefaultImg());

                return skuImagesEntity;

            }).filter(img -> img.getDefaultImg() == 1) //  保存默认的图片
            .collect(Collectors.toList());

            // 批量保存 sku 图片信息
            skuImagesService.saveBatch(skuImagesEntityList);

            // 5.3 保存满减信息、折扣、会员价 mall_sms: sms_sku_ladder、sms_reduction、sms_member_price */
            // 构建待添加的 sku 促销参数信息
            SkuReductionDTO skuReductionDTO = new SkuReductionDTO();

            // 设置 sku id、原价、满减件数、折扣价、折扣状态、价格状态、会员价
            skuReductionDTO.setSkuId(skuInfoEntity.getSkuId());
            skuReductionDTO.setFullCount(sku.getFullCount());
            skuReductionDTO.setDiscount(sku.getDiscount());
            skuReductionDTO.setCountStatus(sku.getCountStatus());
            skuReductionDTO.setReducePrice(sku.getReducePrice());
            skuReductionDTO.setPriceStatus(sku.getPriceStatus());
            skuReductionDTO.setMemberPrice(sku.getMemberPrice());
            skuReductionDTO.setFullPrice(sku.getFullPrice());

            // 保存 sku 促销参数信息
            couponFeignService.saveSkuReductionInfo(skuReductionDTO);

            // 5.4 sku 的销售属性信息：pms_sku_sale_attr_value */
            // 获取 sku 的销售属性信息
            List<Attr> attrParamList = sku.getAttr();

            // 获取 sku 销售属性 id 集合
            Set<Long> salesAttrIdSet = attrParamList.stream().map(Attr::getAttrId).collect(Collectors.toSet());

            // 根据销售属性 id 集合查找销售属性列表
            LambdaQueryWrapper<AttrEntity> attrEntityQw = new LambdaQueryWrapper<>();
            attrEntityQw.in(AttrEntity::getAttrId, salesAttrIdSet);
            List<AttrEntity> salesAttrEntities = attrService.list(attrEntityQw);

            // 如果销售属性列表和销售属性 id 集合长度不一致，则抛出异常
            if (salesAttrEntities.size() != salesAttrIdSet.size())
                throw new BusinessException("销售属性信息不存在！");

            // 将 sku 销售属性封装为 sku销售属性&值 列表
            List<SkuSaleAttrValueEntity> skuSaleAttrValueEntityList = attrParamList.stream().map(attrParam -> {

                // 构建待添加的 sku 销售属性
                SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();

                // 设置属性 id、属性值、sku id
                skuSaleAttrValueEntity.setAttrId(attrParam.getAttrId());
                skuSaleAttrValueEntity.setAttrName(attrParam.getAttrName());
                skuSaleAttrValueEntity.setAttrValue(attrParam.getAttrValue());

                return skuSaleAttrValueEntity;

            }).collect(Collectors.toList());

            // 保存 sku 销售属性列表
            skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntityList);
        }

        // 6.保存 spu 积分信息：mall_sms：sms_spu_bounds */
        // 获取 spu 积分信息
        Bounds bounds = spuInfoVo.getBounds();

        // 如果积分信息不为空，则保存 spu 积分信息
        if (ObjectUtil.isNotEmpty(bounds)) {

            // 构建待添加的 spu 积分信息
            SpuBoundsDTO spuBoundsDTO = new SpuBoundsDTO();

            // 设置 spu id、购买积分、成长积分
            spuBoundsDTO.setSpuId(spuInfoEntity.getId());
            spuBoundsDTO.setBuyBounds(bounds.getBuyBounds());
            spuBoundsDTO.setGrowBounds(bounds.getGrowBounds());

            // 保存 spu 积分信息
            R r = couponFeignService.saveSpuBounds(spuBoundsDTO);

            // 如果返回结果不成功，打印日志
            if (r.getCode() != 0) {
                log.error("调用Coupon服务存储积分信息操作失败");
            }
        }
    }

    /**
     * 构建查询条件
     */
    private QueryWrapper<SpuInfoEntity> buildQueryWrapper(Map<String, Object> params) {

        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();

        // 根据 spu id、spu 名称、spu 描述模糊查询
        String key = (String) params.get("key");
        if(!StringUtils.isEmpty(key)){

            // 需要添加关键字查询
            wrapper.and((w)->{
                w.eq("id",key)
                        .or().like("spu_name",key)
                        .or().like("spu_description",key);
            });
        }

        // 根据 发布状态 查询
        String status = (String) params.get("status");
        if(!StringUtils.isEmpty(status)){
            wrapper.eq("publish_status",status);
        }

        // 根据 分类 id 查询
        String catalogId = (String) params.get("catalogId");
        if(!StringUtils.isEmpty(catalogId) && !"0".equalsIgnoreCase(catalogId)){
            wrapper.eq("catalog_id",catalogId);
        }

        // 根据 品牌 id 查询
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId) && !"0".equalsIgnoreCase(brandId)){
            wrapper.eq("brand_id",brandId);
        }

        return wrapper;
    }
}
